#include "vector3d.h"
#include <cstdlib>
#include <cmath>
#include <iostream>
#include "vector.h"


Vector3D::Vector3D(){
	x = 0.0;
	y = 0.0;
	z = 0.0;
}

Vector3D::Vector3D(const Vector &v){
    if(v.getRow() != 3){
        std::cout <<"Erro no contrutor de Vector3D!"<<std::endl;
        exit(1);
    }
	x = v[0];
	y = v[1];
	z = v[2];
}

Vector3D::Vector3D(double _x, double _y, double _z):x(_x), y(_y), z(_z){
}

Vector3D::~Vector3D(){
}

double Vector3D::operator[](unsigned int _i) const{
    switch(_i){
        case 0:
            return x;
            break;
        case 1:
            return y;
            break;
        case 2:
            return z;
            break;
    }
    std::cout <<"Erro no operador [] de Vector3D!"<<std::endl;
    exit(1);
}

Vector3D& Vector3D::operator=(const Vector3D &_vector){
	if(this != &_vector){
		x = _vector.x;
		y = _vector.y;
		z = _vector.z;
	}
	return *this;
}

bool Vector3D::operator==(const Vector3D &_vector) const{
    if( (x == _vector.x) && (y == _vector.y) && (z == _vector.z) ) return true;
    return false;
}

Vector3D Vector3D::operator*(double _s) const {
	return Vector3D(x*_s, y*_s, z*_s);
}

Vector3D Vector3D::operator+(const Vector3D &_vector) const {
	return Vector3D(x+_vector.x, y+_vector.y, z+_vector.z);
}

Vector3D Vector3D::operator-(const Vector3D &_vector) const {
	return Vector3D(x-_vector.x, y-_vector.y, z-_vector.z);
}

Vector3D Vector3D::operator-() const {
	return Vector3D(-x, -y, -z);
}

Vector3D Vector3D::crossProduct(const Vector3D &_vector) const {
	return Vector3D(y*_vector.z - z*_vector.y, z*_vector.x - x*_vector.z, x*_vector.y - y*_vector.x);
}

double Vector3D::dotProduct(const Vector3D &_vector) const {
	return x*_vector.x + y*_vector.y + z*_vector.z;
}

double Vector3D::length() const {
	return sqrt(this->dotProduct((*this)));
}

double Vector3D::length_2() const {
	return this->dotProduct((*this));
}

Vector3D Vector3D::normalize() const{
	double norm = length();
	if(norm == 0)
	{
        norm = 1;
//	    std::cout <<"Ia ser dividido por zero na normalização! " <<std::endl;
	}

	return Vector3D(x/norm, y/norm, z/norm);
}

double *Vector3D::intoVector() const {
    double *d;
    d = new double[3];
    d[0] = x;
    d[1] = y;
    d[2] = z;

    return d;
}

void Vector3D::print() const {
    std::cout << "[ " <<x << ", " << y << ", " << z <<"]"<<std::endl;
}

Vector Vector3D::toHomogeneousCoordinates() const {
    Vector result(4);
    result[0] = x;
    result[1] = y;
    result[2] = z;
    result[3] = 1.0;
    return result;
}

Vector3D Vector3D::normal(const Vector3D &p1, const Vector3D &p3) {
    Vector3D p2 = *this;
    return (p1 - p2).crossProduct(p3 - p2).normalize();
}

double Vector3D::area(const Vector3D &p1, const Vector3D &p3) {
    Vector3D p2 = *this;
    return ((p1 - p2).crossProduct(p3 - p2).length())/2.0;
}


bool isCollinear(const Vector3D &_p1, const Vector3D &_p2){
    if(_p1 == _p2) return true;

    Vector3D p = _p1.crossProduct(_p2);
    return p.length_2() < ERROR;
}
